#!/usr/bin/env python
#


# test test test

import logging
import wsgiref.handlers
import PyRSS2Gen
import datetime
import time
import random
import os
import math

from google.appengine.ext import webapp
from google.appengine.api import urlfetch
from google.appengine.ext import db
from django.utils import simplejson
from google.appengine.ext.webapp import template
from google.appengine.ext.webapp.util import run_wsgi_app

# dimension of the game
STEP = 3
DIMENSION = STEP * STEP
FIELD_COUNT = DIMENSION * DIMENSION

# Set the debug level
_DEBUG = True

# the default roomno
DEFAULT_ROOM = "001"

# URL parameter for roomno
UP_ROOM = "r"

# URL parameter for the field no
UP_FIELD = "f"

# URL parameter for the content
UP_CONTENT = "c" 

# URL parameter for the id
UP_ID = "i"

# URL parameter value for all reqs
UPV_ALL = "_all"

# security code
SEC_CODE = "sasa"

# contents
CONTENT_NO = "."

# game states
GAME_STATE_OPEN = "o"
GAME_STATE_CLOSED = "c"

# the URL base of the application
base = ""

# init global vars
def init(request):
  global base
  if len(base) == 0:
    base = "http://" + request.headers['Host']
    pass


# the draws (just for logging purposes)
class Draw(db.Model):
  time = db.DateTimeProperty(auto_now_add=True)
  id = db.StringProperty()
  gameId = db.StringProperty()
  roomNo = db.StringProperty()
  field = db.StringProperty()
  num = db.StringProperty()


# the game
class Ggk(db.Model):
  time = db.DateTimeProperty(auto_now_add=True)
  id = db.StringProperty()
  roomNo = db.StringProperty()
  gameState = db.StringProperty()
  playingField = db.StringProperty()
  gamesFinished = db.StringProperty()


# check the security code of the request
def checkSec(request):
  if request.get("c") == SEC_CODE:
    return 1
  else:
    return 0


# check whether the roomno is valid
def checkRoom(roomNo):
  result = False
  if(len(roomNo) > 0):
    result = True
    pass
  return result


# create a new game
def createGame(roomNo, gamesFinished):
  logging.debug("createGame")
  ggk = Ggk()
  ggk.id = str(random.randint(1, 1000000000000000))
  ggk.roomNo = roomNo
  ggk.gameState = GAME_STATE_OPEN
  ggk.playingField = CONTENT_NO * FIELD_COUNT
  ggk.gamesFinished = gamesFinished
  ggk.put()
  return ggk


# get the current game in the given room
# if there is no open game, create a new one
def getCurrentGame(roomNo):
  logging.debug("getCurrentGame")
  ggk = None
  ggks = db.GqlQuery("SELECT * FROM Ggk WHERE roomNo = :1 ORDER BY time DESC LIMIT 1", roomNo)
  for g in ggks:
    ggk = g
    break
  if ggk:
    logging.debug("gameState = " + ggk.gameState)
    pass
  if not ggk:
    ggk = createGame(roomNo, "0")
  elif ggk.gameState == GAME_STATE_CLOSED:
    gf = int(ggk.gamesFinished)+1
    ggk = createGame(roomNo, str(gf))
    pass
  return ggk


# get all games
def getAllGames():
  ggks = db.GqlQuery("SELECT * FROM Ggk ORDER BY time DESC LIMIT 1000")
  return ggks


# get all draws
def getAllDraws():
  draws = db.GqlQuery("SELECT * FROM Draw ORDER BY time DESC LIMIT 1000")
  return draws


# get the req with the given id
def getGgk(id):
  ggk = None
  ggks = db.GqlQuery("SELECT * FROM Ggk WHERE id = :1", id)
  for g in ggks:
    ggk = g
    break
  return ggk


# checks a line, col or sector
def checkPart(ggk, coords, name):
  result = False
  m = []
  for c in coords:
    i = transformCoords(c[0], c[1])
    if ggk.playingField[i-1] <> CONTENT_NO and ggk.playingField[i-1] in m:
      ggk.playingField = ggk.playingField[0:i-1] + CONTENT_NO + ggk.playingField[i:len(ggk.playingField)]
      logging.info("killed no " + str(i) + " : "  + name) 
      result = True
    else:
      m.append(ggk.playingField[i-1])
      pass
    pass
  return result


# transforms semi-eukl coords (upper left = <1,1>)
# in linear coords (1 to FIELD_COUNT)
def transformCoords(x, y):
  linear = ((y-1)*DIMENSION)+x
  return linear


# checks whether the field is full
def checkFull(ggk):
  full = True
  for i in range(0,FIELD_COUNT):
    if ggk.playingField[i] == CONTENT_NO:
      full = False
      break
    pass

  if full:
    ggk.gameState = GAME_STATE_CLOSED
    pass

  return full


# checks the game for duplicate
def checkGame(ggk):
  result = False

  # rows
  for y in range(1, DIMENSION+1):
    row = []
    for x in range(1, DIMENSION+1):
      coord = [x, y]
      row.append(coord)
      pass
    if checkPart(ggk, row, "row"+str(y)):
      result = True
      pass
    pass

  # cols
  for x in range(1, DIMENSION+1):
    col = []
    for y in range(1, DIMENSION+1):
      coord = [x, y]
      col.append(coord)
      pass
    if checkPart(ggk, col, "col"+str(x)):
      result = True
      pass
    pass

  # secs
  for s in range(1, DIMENSION+1):
    ystart = (((s-1)//STEP)*STEP)+1
    xstart = (((s-1)%STEP)*STEP)+1
    sec = []
    for y in range(ystart, ystart+STEP):
      for x in range(xstart, xstart+STEP):
        coord = [x, y]
        sec.append(coord)
        pass
      pass
    if checkPart(ggk, sec, "sec"+str(s)):
      result = True
      pass
    pass

  return result


# get the number of reqs
def getGgkCount():
  q = db.GqlQuery("SELECT * FROM Ggk")
  count = q.count()
  return count


# handler to deliver a rss feed for the requests  
class RssHandler(webapp.RequestHandler):

  def get(self):
    init(self.request)

    rss = PyRSS2Gen.RSS2(
      title = "Geegoku",
      link = base + "/html",
      description = "all games",
      lastBuildDate = datetime.datetime.now(),
      items = []
      )

    for draw in getAllDraws():
      rss.items.append(
        PyRSS2Gen.RSSItem(
          title = str(draw.roomNo) + " : " + str(draw.gameId) + " : " + str(draw.field) + " : " + str(draw.num),
          description = str(draw.id),
          guid = PyRSS2Gen.Guid(base + "/html?" + UP_ID + "=" + draw.gameId),
          pubDate = draw.time
          )
        )
      
    rss.write_xml(self.response.out)


# handler to put a plugg into the db
class DrawHandler(webapp.RequestHandler):

  def get(self):
    logging.debug("DrawHandler")
    init(self.request)

    roomNo = self.request.get(UP_ROOM)

    if not checkRoom(roomNo):
      return

    ggk = getCurrentGame(roomNo)
    logging.debug("game state: " + ggk.gameState)
    if ggk.gameState == GAME_STATE_OPEN:
      fieldNo = int(self.request.get(UP_FIELD))
      content = self.request.get(UP_CONTENT)
      playingField = ggk.playingField
      logging.debug("draw field: " + str(fieldNo) + " = " + content + " (" + playingField + ")")
      currentContent = playingField[fieldNo-1]
      logging.debug("currentContent: " + currentContent)
      draw = Draw()
      draw.id = str(random.randint(1, 1000000000000000))
      draw.field = str(fieldNo)
      draw.num = content
      draw.gameId = ggk.id
      draw.roomNo = ggk.roomNo
      ggk.playingField = playingField[0:fieldNo-1] + content + playingField[fieldNo:len(playingField)]
      draw.put()
      ggk.put()
      pass
    
    self.redirect("/state?r=" + roomNo)



# handler to get the current state
class StateHandler(webapp.RequestHandler):

  def get(self):
    logging.debug("StateHandler")
    init(self.request)

    state = None
    roomNo = self.request.get(UP_ROOM)

    if not checkRoom(roomNo):
      return

    ggk = getCurrentGame(roomNo)

    put = False
    if checkGame(ggk):
      put = True
      pass
    if checkFull(ggk):
      put = True
      pass
    if put:
      ggk.put()
      pass

    state = {}
    state['gameId'] = ggk.id
    state['gameState'] = ggk.gameState
    state['gamesFinished'] = ggk.gamesFinished
    state['playingField'] = ggk.playingField

    logging.debug("state = " + simplejson.dumps(state))

    self.response.headers['Content-Type'] = 'application/json'
    self.response.out.write(simplejson.dumps(state))



# create a new game 
class CreateGameHandler(webapp.RequestHandler):

  def get(self):
    init(self.request)
    roomNo = self.request.get(UP_ROOM)

    if not checkRoom(roomNo):
      return

    createGame(roomNo)
    self.redirect("/state?r=" + roomNo)

    

# print a game in HTML to out
def printGame(ggk, out):
  out.write(ggk.playingField + "<br>")


# handler to get the Reqs as HTML 
class HtmlHandler(webapp.RequestHandler):

  def get(self):
    init(self.request)

    id = self.request.get(UP_ID)
    
    self.response.out.write("<html><body>")                                

    if len(id) > 0:
      ggk = getGgk(id)
      if ggk:
        printGame(ggk, self.response.out)
        pass
      pass
    else:
      for ggk in getAllGames():
        printGame(ggk, self.response.out)
        pass
      pass

    self.response.out.write("</body></html>")
      

# get HTML page
class MainHandler(webapp.RequestHandler):
  def get(self):

    # Construct the path to the template
    directory = os.path.dirname(__file__)
    path = os.path.join(directory, 'templates', 'index.html')

    self.response.out.write(template.render(path, {}, debug=_DEBUG));


def main():
  application = webapp.WSGIApplication([('/', MainHandler),
                                        ('/rss', RssHandler),
                                        ('/html', HtmlHandler),
                                        ('/draw', DrawHandler),
                                        ('/cg', CreateGameHandler),
                                        ('/state', StateHandler)],
                                       debug=True)
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main()
